package com.bsg.upm.http;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.ResourceBundle;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

/**
 * HttpClient tool
 * 
 * @author HCK
 *
 */
public class HttpClientUtils {

	public static final String METHOD_GET = "GET";
	public static final String METHOD_POST = "POST";
	public static final String METHOD_PUT = "PUT";
	public static final String METHOD_DELETE = "DELETE";

	/**
	 * log
	 */
	private static Logger logger = Logger.getLogger("HttpClientUtils");

	public static RequestConfig requestConfig = null;

	static {
		Builder build = RequestConfig.custom();
		try {
			ResourceBundle resource = ResourceBundle.getBundle("config/http-timeout");
			// 从服务器读取数据的timeout
			String socketTimeout = resource.getString("http.socket.timeout");
			if (StringUtils.isNumeric(socketTimeout)) {
				build.setSocketTimeout(Integer.parseInt(socketTimeout));
			}

			// 和服务器建立连接的timeout
			String connectTimeout = resource.getString("http.connect.timeout");
			if (StringUtils.isNumeric(connectTimeout)) {
				build.setConnectTimeout(Integer.parseInt(connectTimeout));
			}

			// 从连接池获取连接的timeout
			String connectionRequestTimeout = resource.getString("http.connection.request.timeout");
			if (StringUtils.isNumeric(connectionRequestTimeout)) {
				build.setConnectionRequestTimeout(Integer.parseInt(connectionRequestTimeout));
			}
		} catch (Exception e) {
		}
		requestConfig = build.build();
	}

	/**
	 * send GET requests
	 * 
	 * @param httpUrl
	 * @param showLog
	 * @return
	 * @throws HttpConnectionException
	 * @throws HttpClientException
	 */
	public static RespJson sendHttpGet(String httpUrl, boolean showLog)
			throws HttpConnectionException, HttpClientException {
		if (showLog) {
			logger.info("HTTP Request URL：" + httpUrl);
			logger.info("HTTP Request Method：GET");
		}

		HttpGet httpGet = new HttpGet(httpUrl);
		return sendHttp(httpGet, showLog);
	}

	/**
	 * send POST requests
	 * 
	 * @param httpUrl
	 * @param jsonParam
	 * @param showLog
	 * @return
	 * @throws HttpConnectionException
	 * @throws HttpClientException
	 */
	public static RespJson sendHttpPost(String httpUrl, String jsonParam, boolean showLog)
			throws HttpConnectionException, HttpClientException {
		if (showLog) {
			logger.info("HTTP Request URL：" + httpUrl);
			logger.info("HTTP Request Method：POST");
			logger.info("HTTP Request Parameter：" + jsonParam);
		}

		HttpPost httpPost = new HttpPost(httpUrl);
		if (jsonParam != null) {
			StringEntity stringEntity = new StringEntity(jsonParam, "UTF-8");
			stringEntity.setContentType("application/json");
			httpPost.setEntity(stringEntity);
		}
		return sendHttp(httpPost, showLog);
	}

	/**
	 * send PUT requests
	 * 
	 * @param httpUrl
	 * @param jsonParam
	 * @param showLog
	 * @return
	 * @throws HttpConnectionException
	 * @throws HttpClientException
	 */
	public static RespJson sendHttpPut(String httpUrl, String jsonParam, boolean showLog)
			throws HttpConnectionException, HttpClientException {
		if (showLog) {
			logger.info("HTTP Request URL：" + httpUrl);
			logger.info("HTTP Request Method：PUT");
			logger.info("HTTP Request Parameter：" + jsonParam);
		}

		HttpPut httpPut = new HttpPut(httpUrl);
		if (jsonParam != null) {
			StringEntity stringEntity = new StringEntity(jsonParam, "UTF-8");
			stringEntity.setContentType("application/json");
			httpPut.setEntity(stringEntity);
		}
		return sendHttp(httpPut, showLog);
	}

	/**
	 * send DELETE requests
	 * 
	 * @param httpUrl
	 * @param showLog
	 * @return
	 * @throws HttpConnectionException
	 * @throws HttpClientException
	 */
	public static RespJson sendHttpDelete(String httpUrl, boolean showLog)
			throws HttpConnectionException, HttpClientException {
		if (showLog) {
			logger.info("HTTP Request URL：" + httpUrl);
			logger.info("HTTP Request Method：DELETE");
		}
		HttpDelete httpDelete = new HttpDelete(httpUrl);
		return sendHttp(httpDelete, showLog);
	}

	/**
	 * sent HTTP requests
	 * 
	 * @param httpMethod
	 * @param showLog
	 * @return
	 * @throws HttpConnectionException
	 * @throws HttpClientException
	 */
	private static RespJson sendHttp(Object httpMethod, boolean showLog)
			throws HttpConnectionException, HttpClientException {
		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		try {
			httpClient = HttpClients.createDefault();
			if (httpMethod instanceof HttpGet) {
				HttpGet httpGet = (HttpGet) httpMethod;
				httpGet.setConfig(requestConfig);
				response = httpClient.execute(httpGet);
			} else if (httpMethod instanceof HttpPost) {
				HttpPost httpPost = (HttpPost) httpMethod;
				httpPost.setConfig(requestConfig);
				response = httpClient.execute(httpPost);
			} else if (httpMethod instanceof HttpPut) {
				HttpPut httpPut = (HttpPut) httpMethod;
				httpPut.setConfig(requestConfig);
				response = httpClient.execute(httpPut);
			} else if (httpMethod instanceof HttpDelete) {
				HttpDelete httpDelete = (HttpDelete) httpMethod;
				httpDelete.setConfig(requestConfig);
				response = httpClient.execute(httpDelete);
			}

			int statusCode = response.getStatusLine().getStatusCode();
			if (showLog) {
				logger.info("HTTP Response Status Code：" + statusCode);
			}

			HttpEntity entity = response.getEntity();
			String responseContent = null;
			if (entity != null) {
				responseContent = EntityUtils.toString(entity, "UTF-8");
			}
			if (showLog) {
				logger.info("HTTP Response ：" + responseContent + "\r\n");
			}

			if (httpMethod instanceof HttpGet || httpMethod instanceof HttpPut) {
				if (statusCode == HttpStatus.SC_OK) {
					Object resJson = convertToJson(responseContent);
					return RespJsonFactory.buildOK(resJson);
				}
			} else if (httpMethod instanceof HttpPost) {
				if (statusCode == HttpStatus.SC_CREATED) {
					Object resJson = convertToJson(responseContent);
					return RespJsonFactory.buildCreated(resJson);
				}
			} else if (httpMethod instanceof HttpDelete) {
				if (statusCode == HttpStatus.SC_NO_CONTENT) {
					return RespJsonFactory.buildNoContent();
				}
			}

			return RespJsonFactory.build(HttpStatus.SC_INTERNAL_SERVER_ERROR, "调用接口异常:" + formate(responseContent));
		} catch (HttpHostConnectException e) {
			throw new HttpConnectionException(e.getMessage());
		} catch (SocketTimeoutException e) {
			throw new HttpConnectionException(e.getMessage());
		} catch (Exception e) {
			throw new HttpClientException(e.getMessage());
		} finally {
			try {
				if (response != null) {
					response.close();
				}
				if (httpClient != null) {
					httpClient.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private static Object convertToJson(String responseContent) {
		if (responseContent.startsWith("{")) {
			return JSONObject.parseObject(responseContent);
		} else if (responseContent.startsWith("[")) {
			return JSONArray.parseArray(responseContent);
		} else {
			return null;
		}
	}

	private static String formate(String responseContent) {
		if (responseContent.startsWith("{")) {
			return JSONObject.parseObject(responseContent).getString("category");
		} else {
			return responseContent;
		}
	}
}
